package com.lpz.wdbc;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;

import com.lpz.wdbc.util.StringUtils;


/**
 * 构建查询条件
 * @author wangcb
 * @date 2017年5月5日
 */

public class Condition<T> {
    
   
    private StringBuilder sqlBuilder = null;
    
    @Column
    private List<Object> params = null;
    
    private Class<T> clazz = null;
    
    private Map<String,String> propColumnMap = null;
    
    
    public StringBuilder getSqlBuilder(){
        
        return this.sqlBuilder;
    }
    
    public List<Object> getParams(){
        return this.params;
    }
    
    Condition(){
        propColumnMap= new HashMap<>();
        this.clazz  =  (Class <T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[ 0 ];
        this.sqlBuilder = new StringBuilder();
        params = new ArrayList<>();
        Field[] fields=clazz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            String column = "";   
            Field f = fields[i];
            Column c =  f.getAnnotation(Column.class);
            if(c != null) column = c.name();
            else column = StringUtils.camelToUnderline(f.getName());
            
            propColumnMap.put(f.getName(), column);
        }
    }
    
    public  Condition<T>  andEq(String property, Object value){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" and ");
        sqlBuilder.append(column);
        sqlBuilder.append("=? ");
        params.add(value);
        return this;
    }
    
    public  Condition<T>  andGt(String property, Object value){
        return andGt(property,value,false);
    }
    
    public  Condition<T>  andGt(String property, Object value, boolean eq){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" and ");
        sqlBuilder.append(column);
        sqlBuilder.append(">");
        if(eq) sqlBuilder.append("=");
        sqlBuilder.append("? ");
        params.add(value);
        return this;
    }
    
    public  Condition<T>  andLt(String property, Object value, boolean eq){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" and ");
        sqlBuilder.append(column);
        sqlBuilder.append("<");
        if(eq) sqlBuilder.append("=");
        sqlBuilder.append("? ");
        params.add(value);
        return this;
    }
    
    public  Condition<T>  andLt(String property, Object value){
        
        return andLt(property,value,false);
    }
    
    public  Condition<T>  andBetween(String property,Object svalue, Object evalue){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" and ");
        sqlBuilder.append(column);
        sqlBuilder.append(" between ");
        sqlBuilder.append(" ? ");
        sqlBuilder.append(" and ");
        sqlBuilder.append(" ? ");
        params.add(svalue);
        params.add(evalue);
        return this;
    }
    
    public  Condition<T>  andLike(String property, Object value){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" and ");
        sqlBuilder.append(column);
        sqlBuilder.append(" like ");
        sqlBuilder.append(" ? ");
        params.add(value);
        return this;
    }
    
    public Condition<T> andIn(String property, List<Object> values){
        if(values==null || values.isEmpty()) return this;
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" and ");
        sqlBuilder.append(column);
        sqlBuilder.append(" in ( ");
        for (int i = 0; i < values.size(); i++) {
            sqlBuilder.append("?"); 
           if(i < (values.size()-1)){
               sqlBuilder.append(","); 
           }
            Object parm = values.get(i);
            params.add(parm);
        }
        sqlBuilder.append(" ) ");
        return this;
    }
    
    public Condition<T> and(Condition<T> c){
        sqlBuilder.append(" and ");
        sqlBuilder.append(" ( ");
        sqlBuilder.append(c.getSqlBuilder());
        sqlBuilder.append(" ) ");
        params.addAll(c.getParams());
        return this;
    }
    
    
    public Condition<T> orEq(String property, Object value){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" or ");
        sqlBuilder.append(column);
        sqlBuilder.append("=");
        sqlBuilder.append(" ? ");
        params.add(value);
        return this;
    }
    
    public Condition<T> orGt(String property, Object value){
        return orGt(property, value,false);
    }
    
    public Condition<T> orGt(String property, Object value, boolean eq){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" or ");
        sqlBuilder.append(column);
        sqlBuilder.append(">");
        if(eq) sqlBuilder.append("=");
        sqlBuilder.append(" ? ");
        params.add(value);
        return this;
    }
    
    public Condition<T>  orLt(String property, Object value, boolean eq){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" or ");
        sqlBuilder.append(column);
        sqlBuilder.append("<");
        if(eq) sqlBuilder.append("=");
        sqlBuilder.append(" ? ");
        params.add(value);
        return this;
    }
    
    public Condition<T> orLt(String property, Object value){
        
       return orLt(property, value,false);
    }
    
    public Condition<T> orBetween(String property,Object svalue, Object evalue){
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" or ");
        sqlBuilder.append(column);
        sqlBuilder.append(" between ");
        sqlBuilder.append(" ? ");
        sqlBuilder.append(" and ");
        sqlBuilder.append(" ? ");
        params.add(svalue);
        params.add(evalue);
        return this;
    }
    
    public Condition<T> orLike(String property, Object value){
        
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" or ");
        sqlBuilder.append(column);
        sqlBuilder.append(" like ");
        sqlBuilder.append(" ? ");
        params.add(value);
        return this;
    }
    
    public Condition<T> orIn(String property, List<Object> values){
        
        if(values==null || values.isEmpty()) return this;
        String column = propColumnMap.get(property);
        if(StringUtils.isEmpty(column)) column = property;
        sqlBuilder.append(" or ");
        sqlBuilder.append(column);
        sqlBuilder.append(" in ( ");
        for (int i = 0; i < values.size(); i++) {
            sqlBuilder.append("?"); 
           if(i < (values.size()-1)){
               sqlBuilder.append(","); 
           }
            Object parm = values.get(i);
            params.add(parm);
        }
        sqlBuilder.append(" ) ");
        return this;
    }
    
    
    public Condition<T> or(Condition<T> c){
        
        sqlBuilder.append(" or ");
        sqlBuilder.append(" ( ");
        sqlBuilder.append(c.getSqlBuilder());
        sqlBuilder.append(" ) ");
        params.addAll(c.getParams());
        return this;
    }
    
}
